﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;
using System.Dynamic;
using System.Runtime.Serialization;
using CSharpKit.Threading.Tasks;

namespace CSharpKit.Numerics.LinearAlgebra
{
    /// <summary>
    /// 稠密矩阵存储(默认行主序)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    public class MatrixStorageDense<T> : MatrixStorage<T>
        where T : struct, IFormattable, IEquatable<T>
    {
        #region Constructors

        public MatrixStorageDense(int rows, int columns)
            : this(rows, columns, new T[rows * columns]) { }

        public MatrixStorageDense(int rows, int columns, T[] data)
            : base(rows, columns)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            if (data.Length != rows * columns)
            {
                throw new ArgumentOutOfRangeException(nameof(data),
                    string.Format(Resources.Numerics.ArgumentArrayWrongLength, rows * columns));
            }

            _Data = data;

            _IsDense = true;
            _IsMutableFully = true;
            _Order = Matrix<T>.MajorOrder;
        }

        #endregion


        #region Data - 数据

        private T[] _Data;
        [DataMember(Order = 1)]
        public T[] Data => _Data;

        #endregion


        #region Indexer - 索引器

        internal override T At(int row, int col)
        {
            return Data[ElementPosition(row, col)];
        }
        internal override void At(int row, int col, T tvalue)
        {
            Data[ElementPosition(row, col)] = tvalue;
        }
        internal override int ElementPosition(int row, int col)
        {
            int pos = 0;

            switch (Order)
            {
                case MajorOrders.Column:
                    pos = (col * RowCount) + row;
                    break;

                case MajorOrders.Row:
                    pos = (row * ColumnCount) + col;
                    break;

                default:
                    throw new Exception();
            }

            return pos;
        }

        #endregion



        public static MatrixStorageDense<T> OfInit(int rows, int columns, Func<int, int, T> init)
        {
            var storage = new MatrixStorageDense<T>(rows, columns);
            int index = 0;
            for (var j = 0; j < columns; j++)
            {
                for (var i = 0; i < rows; i++)
                {
                    storage.Data[index++] = init(i, j);
                }
            }
            return storage;
        }

        public static MatrixStorageDense<T> OfDiagonalInit(int rows, int columns, Func<int, T> init)
        {
            var storage = new MatrixStorageDense<T>(rows, columns);
            
            int index = 0;
            int stride = rows + 1;  // 因为列主序

            for (var i = 0; i < System.Math.Min(rows, columns); i++)
            {
                storage.Data[index] = init(i);
                index += stride;
            }

            return storage;
        }

        public static MatrixStorageDense<T> OfArray(T[,] array)
        {
            var storage = new MatrixStorageDense<T>(array.GetLength(0), array.GetLength(1));
            int index = 0;
            for (var j = 0; j < storage.ColumnCount; j++)
            {
                for (var i = 0; i < storage.RowCount; i++)
                {
                    storage.Data[index++] = array[i, j];
                }
            }
            return storage;
        }








        


        //}}@@@
    }


}
